From ea3cb31cec6f03606dfd37293fc8d71bf03e4b1e Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 30 Jun 2014 18:36:27 -0700 Subject: [PATCH] Meta-packages --- src/cargo/core/registry.rs | 14 ++++- src/cargo/core/source.rs | 2 +- src/cargo/ops/cargo_read_manifest.rs | 94 +++++++++++++++++++++++----- src/cargo/ops/cargo_rustc.rs | 1 - tests/test_cargo_compile_git_deps.rs | 74 ++++++++++++++++++++++ 5 files changed, 165 insertions(+), 20 deletions(-) diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index f150c7880..6a2d6feff 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -29,6 +29,7 @@ impl<'a> PackageRegistry<'a> { config: &'a mut Config<'a>) -> CargoResult> { let mut reg = PackageRegistry::empty(config); + let source_ids = dedup(source_ids); for id in source_ids.iter() { try!(reg.load(id, false)); @@ -90,7 +91,7 @@ impl<'a> PackageRegistry<'a> { // Get the summaries for summary in (try!(source.list())).iter() { - assert!(!dst.contains(summary), "duplicate summaries"); + assert!(!dst.contains(summary), "duplicate summaries: {}", summary); dst.push(summary.clone()); // self.summaries.push(summary.clone()); } @@ -106,6 +107,17 @@ impl<'a> PackageRegistry<'a> { } } +fn dedup(ids: Vec) -> Vec { + let mut seen = vec!(); + + for id in ids.move_iter() { + if seen.contains(&id) { continue; } + seen.push(id); + } + + seen +} + impl<'a> Registry for PackageRegistry<'a> { fn query(&mut self, dep: &Dependency) -> CargoResult> { let overrides = try!(self.overrides.query(dep)); // this can never fail in practice diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 6e7192a35..a9aedb749 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -61,7 +61,7 @@ pub enum Location { Remote(Url), } -#[deriving(Clone,PartialEq)] +#[deriving(Clone, PartialEq, Eq)] pub struct SourceId { pub kind: SourceKind, pub location: Location, diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs index 91dbc6361..e21472af1 100644 --- a/src/cargo/ops/cargo_read_manifest.rs +++ b/src/cargo/ops/cargo_read_manifest.rs @@ -1,8 +1,9 @@ use std::collections::HashSet; -use std::io::File; +use std::io::{File, fs}; use util; use core::{Package,Manifest,SourceId}; -use util::{CargoResult, human, important_paths}; +use util::{CargoResult, human}; +use util::important_paths::find_project_manifest_exact; pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec)> @@ -22,26 +23,85 @@ pub fn read_package(path: &Path, source_id: &SourceId) Ok((Package::new(manifest, path, source_id), nested)) } -pub fn read_packages(path: &Path, source_id: &SourceId) - -> CargoResult> +pub fn read_packages(path: &Path, + source_id: &SourceId) -> CargoResult> { - return read_packages(path, source_id, &mut HashSet::new()); + let mut all_packages = Vec::new(); + let mut visited = HashSet::::new(); - fn read_packages(path: &Path, source_id: &SourceId, - visited: &mut HashSet) -> CargoResult> { - if !visited.insert(path.clone()) { return Ok(Vec::new()) } + log!(5, "looking for root package: {}, source_id={}", path.display(), source_id); + try!(process_possible_package(path, &mut all_packages, source_id, &mut visited)); - let manifest = try!(important_paths::find_project_manifest_exact(path, - "Cargo.toml")); - let (pkg, nested) = try!(read_package(&manifest, source_id)); - let mut ret = vec![pkg]; + try!(walk(path, true, |dir| { + log!(5, "looking for child package: {}", dir.display()); + if dir.filename_str() == Some(".git") { return Ok(false); } + if dir.join(".git").is_dir() { return Ok(false); } + try!(process_possible_package(dir, &mut all_packages, source_id, &mut visited)); + Ok(true) + })); - for p in nested.iter() { - ret.push_all(try!(read_packages(&path.join(p), - source_id, - visited)).as_slice()); + if all_packages.is_empty() { + Err(human(format!("Could not find Cargo.toml in `{}`", path.display()))) + } else { + log!(5, "all packages: {}", all_packages); + Ok(all_packages) + } +} + +fn walk(path: &Path, is_root: bool, callback: |&Path| -> CargoResult) -> CargoResult<()> { + if path.is_dir() { + if !is_root { + let continues = try!(callback(path)); + if !continues { log!(5, "Found submodule at {}", path.display()); return Ok(()); } } - Ok(ret) + for dir in try!(fs::readdir(path)).iter() { + try!(walk(dir, false, |x| callback(x))) + } + } + + Ok(()) +} + +fn process_possible_package(dir: &Path, + all_packages: &mut Vec, + source_id: &SourceId, + visited: &mut HashSet) -> CargoResult<()> { + + if !has_manifest(dir) { return Ok(()); } + + let packages = try!(read_nested_packages(dir, source_id, visited)); + push_all(all_packages, packages); + + Ok(()) +} + +fn has_manifest(path: &Path) -> bool { + find_project_manifest_exact(path, "Cargo.toml").is_ok() +} + +fn read_nested_packages(path: &Path, source_id: &SourceId, + visited: &mut HashSet) -> CargoResult> { + if !visited.insert(path.clone()) { return Ok(Vec::new()) } + + let manifest = try!(find_project_manifest_exact(path, "Cargo.toml")); + + let (pkg, nested) = try!(read_package(&manifest, source_id)); + let mut ret = vec![pkg]; + + for p in nested.iter() { + ret.push_all(try!(read_nested_packages(&path.join(p), + source_id, + visited)).as_slice()); + } + + Ok(ret) +} + +fn push_all(set: &mut Vec, packages: Vec) { + for package in packages.move_iter() { + if set.contains(&package) { continue; } + + set.push(package) } } diff --git a/src/cargo/ops/cargo_rustc.rs b/src/cargo/ops/cargo_rustc.rs index 9b4489d79..ef107fca2 100644 --- a/src/cargo/ops/cargo_rustc.rs +++ b/src/cargo/ops/cargo_rustc.rs @@ -203,7 +203,6 @@ fn prepare_rustc(root: &Path, target: &Target, crate_types: Vec<&str>, build_base_args(&mut args, target, crate_types, cx); build_deps_args(&mut args, cx); - util::process("rustc") .cwd(root.clone()) .args(args.as_slice()) diff --git a/tests/test_cargo_compile_git_deps.rs b/tests/test_cargo_compile_git_deps.rs index c587d00e7..62370c11d 100644 --- a/tests/test_cargo_compile_git_deps.rs +++ b/tests/test_cargo_compile_git_deps.rs @@ -227,6 +227,7 @@ test!(cargo_compile_git_dep_tag { cargo::util::process(project.bin("foo")), execs().with_stdout("hello world\n")); }) + test!(cargo_compile_with_nested_paths { let git_project = git_repo("dep1", |project| { project @@ -302,6 +303,79 @@ test!(cargo_compile_with_nested_paths { execs().with_stdout("hello world\n")); }) +test!(cargo_compile_with_meta_package { + let git_project = git_repo("meta-dep", |project| { + project + .file("dep1/Cargo.toml", r#" + [project] + + name = "dep1" + version = "0.5.0" + authors = ["carlhuda@example.com"] + + [[lib]] + + name = "dep1" + "#) + .file("dep1/src/dep1.rs", r#" + pub fn hello() -> &'static str { + "this is dep1" + } + "#) + .file("dep2/Cargo.toml", r#" + [project] + + name = "dep2" + version = "0.5.0" + authors = ["carlhuda@example.com"] + + [[lib]] + + name = "dep2" + "#) + .file("dep2/src/dep2.rs", r#" + pub fn hello() -> &'static str { + "this is dep2" + } + "#) + }).assert(); + + let p = project("parent") + .file("Cargo.toml", format!(r#" + [project] + + name = "parent" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.dep1] + + version = "0.5.0" + git = "file:{}" + + [dependencies.dep2] + + version = "0.5.0" + git = "file:{}" + + [[bin]] + + name = "parent" + "#, escape_path(&git_project.root()), escape_path(&git_project.root()))) + .file("src/parent.rs", + main_file(r#""{} {}", dep1::hello(), dep2::hello()"#, ["dep1", "dep2"]).as_slice()); + + p.cargo_process("cargo-build") + .exec_with_output() + .assert(); + + assert_that(&p.bin("parent"), existing_file()); + + assert_that( + cargo::util::process(p.bin("parent")), + execs().with_stdout("this is dep1 this is dep2\n")); +}) + test!(cargo_compile_with_short_ssh_git { let url = "git@github.com:a/dep"; -- 2.30.2